﻿using System;
using System.Windows.Input;
using System.Collections.Generic;
using AccessControl.Wpf.Commands;
using AccessControl.Wpf.Events.ViewModels;
using AccessControl.Contracts.Models;
using Action = System.Action;
using AccessControl.Gateway.Managers;
using AccessControl.Wpf.Settings.ViewModels;
using AccessControl.Wpf.Reports.ViewModels;
using AccessControl.Wpf.Entries.ViewModels;
using AccessControl.Wpf.Maps.ViewModels;
using System.Threading;
using System.Windows.Threading;

namespace AccessControl.Wpf.ViewModels
{
	class MainViewModel : ActiveItemViewModelManager
	{
		#region Fields

        private bool _IsBusy;
		private ViewModel _EventsViewModel = null;
		private string _OperatorUserName = string.Empty, _OperatorPassword = string.Empty;
        private static readonly DispatcherSynchronizationContext _synchronizationContext = new DispatcherSynchronizationContext();

		#endregion

		#region Public Constructor

		/// <summary>
		/// Initializes a new instance of the <see cref="MainViewModel"/> class.
		/// </summary>
		/// <remarks></remarks>
		public MainViewModel()
		{
		}

		#endregion

		#region Public Properties

		/// <summary>
		/// Gets or sets the events view model.
		/// </summary>
		/// <value>The events view model.</value>
		/// <remarks></remarks>
		public ViewModel EventsViewModel
		{
			get { return _EventsViewModel; }
			set
			{
				if (_EventsViewModel != value)
				{
					_EventsViewModel = value;
					NotifyPropertyChanged("EventsViewModel");
				}
			}
		}

		public string OperatorUserName
		{
			get { return _OperatorUserName; }
			set
			{
				if (_OperatorUserName != value)
				{
					_OperatorUserName = value;
					NotifyPropertyChanged("OperatorUserName");
				}
			}
		}

        public bool IsBusy
        {
            get { return _IsBusy; }
            set
            {
                if (_IsBusy != value)
                {
                    _IsBusy = value;
                    NotifyPropertyChanged("IsBusy");
                }
            }
        }

		public string OperatorPassword
		{
			get { return _OperatorPassword; }
			set
			{
				if (_OperatorPassword != value)
				{
					_OperatorPassword = value;
					NotifyPropertyChanged("OperatorPassword");
				}
			}
		}
		
		
		#endregion

		#region Commands

		public ICommand LoginCommand
		{
			get { return new CommandBase(new Action(Login)); }
		}

		/// <summary>
		/// Gets the logout command.
		/// </summary>
		/// <remarks></remarks>
		public ICommand LogoutCommand
		{
			get { return new CommandBase(new Action(Logout)); }
		}

		public ICommand ShowEntryCommand
		{
			get { return new CommandBaseOfT<IEntry>(new Action<IEntry>(ShowEntry)); }
		}

		public ICommand ShowEntryOnMapCommand
		{
			get { return new CommandBaseOfT<IEntry>(new Action<IEntry>(ShowEntryOnMap)); }
		}

		#endregion

		#region Private Members

		private void Login()
		{
			/* First of all */
            IsBusy = true;
            /* And handle in another thread */
            new Thread(new ThreadStart(HandleLoginRequest)) { IsBackground = true }.Start();			
		}

        private void HandleLoginRequest()
        {
            bool result = Session.Instance.Login(OperatorUserName, OperatorPassword);
            _synchronizationContext.Post(HandleLoginCompleted, result);
        }

        private void HandleLoginCompleted(object o)
        {
            bool result = (bool)o;

            /* First of all */
            IsBusy = false;

            if (!result)
            {
                MessagingService.Show("Could not login to the system.Please recheck user name and password", "AccessControl",
                                        System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Exclamation);
                return;
            }

            /* And now initialize the view models */
            ViewModels.Add(new SettingsViewModel(Session.Instance.SettingsService, MessagingService)
            {
                Name = "Settings",
                MessagingService = MessagingService,
                PopupService = PopupService
            });

            ViewModels.Add(new ReportsViewModel(Session.Instance.ReportsService, Session.Instance.SettingsService)
            {
                Name = "Reports",
                MessagingService = MessagingService,
                PopupService = PopupService
            });

            ViewModels.Add(new EntriesViewModel(Session.Instance.EntriesManager)
            {
                Name = "Entries",
                MessagingService = MessagingService,
                PopupService = PopupService
            });

            ViewModels.Add(new MapsViewModel(Session.Instance.MapsManager)
            {
                Name = "Map",
                MessagingService = MessagingService,
                PopupService = PopupService
            });

            EventsViewModel = new EventsViewModel(Session.Instance.EventsManager)
            {
                Name = "Events",
                MessagingService = MessagingService,
                PopupService = PopupService
            };

            /* And select the entries view model to be the active one */
            ActiveItem = ViewModels[2];
        }

		/// <summary>
		/// Logouts this instance.
		/// </summary>
		/// <remarks></remarks>
		private void Logout()
		{
			ViewModels.Clear();
			ActiveItem = null;
			Session.Instance.Logout();
		}

		private void ShowEntry(IEntry entry)
		{
			EntriesViewModel entriesViewModel = null;

			/* First find the entries view model */
			foreach (ViewModel viewModel in ViewModels)
			{
				if (viewModel is EntriesViewModel)
				{
					entriesViewModel = viewModel as EntriesViewModel;
					break;
				}
			}

			/* Validate */
			if (entriesViewModel == null)
				return;

			/* Make sure we have that entry there */
			foreach (IEntry existingEntry in entriesViewModel.EntriesManager.Items)
			{
				/* If the same one */
				if (existingEntry.Id == entry.Id)
				{
					/* Select it */
					entriesViewModel.SelectedEntry = existingEntry;
					break;
				}
			}

			/* And set the entries view model to be our primary display item */
			ActiveItem = entriesViewModel;
		}

		private void ShowEntryOnMap(IEntry entry)
		{
			double xPos = 0, yPos = 0, tmp;
			MapsViewModel mapsViewModel = null;

			/* First find the entries view model */
			foreach (ViewModel viewModel in ViewModels)
			{
				if (viewModel is MapsViewModel)
				{
					mapsViewModel = viewModel as MapsViewModel;
					break;
				}
			}

			/* Validate */
			if (mapsViewModel == null)
				return;

			/* Run on the map items */
			foreach (IMap mapItem in mapsViewModel.MapsManager.Items)
			{
				foreach (IMapEntry mapEntry in mapItem.Entries)
				{
					/* If we have found it */
					if (mapEntry.Id == entry.Id)
					{
						/* Set the maps as the active item */
						ActiveItem = mapsViewModel;

						/* Make sure we see it */
						xPos = mapsViewModel.LeftOffset;
						yPos = mapsViewModel.TopOffset;
						if (mapEntry.PositionOnMap.X < (mapsViewModel.VisibleWidth - xPos))
						{
							while ((mapsViewModel.VisibleWidth - xPos > mapEntry.PositionOnMap.X) && (xPos < 0))
								++xPos;
						}
						else
						{
							while (mapsViewModel.VisibleWidth - xPos < mapEntry.PositionOnMap.X + 30)
								--xPos;
						}

						if (mapEntry.PositionOnMap.Y < (mapsViewModel.VisibleHeight - yPos))
						{
							while ((mapsViewModel.VisibleHeight - yPos > mapEntry.PositionOnMap.Y) && (yPos < 0))
								++yPos;
						}
						else
						{
							while (mapsViewModel.VisibleHeight - yPos < mapEntry.PositionOnMap.Y + 30)
								--yPos;
						}

						/* Set the matching offsets */
						mapsViewModel.LeftOffset = xPos;
						mapsViewModel.TopOffset = yPos;						
						return;
					}
				}
			}

			/* If we got here we didn't find the entry */
			MessagingService.Show("Entry doesn't appear on the map", "AccessControl", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Information);
		}

		#endregion
	}
}
